import javax.swing.*;
import javax.swing.event.*; 
import java.awt.*;
import java.awt.event.*;

public class ControlPanel extends JPanel 
	implements ActionListener,DocumentListener,FocusListener
{

    /**
     *
     */
    private static final long serialVersionUID = 1L;
    JButton btnSet,btnSolve;
    JTextArea boardDef;
    JComboBox speedSel;
    SudokuApplet parent;
    String oldText;
    JLabel lblStatus;
    ValidateThread t;

    public ControlPanel(SudokuApplet p)
    {
        super();
        t = null;
        parent = p;
        JPanel pnl = new JPanel();
        add(pnl);
        GridBagConstraints c = new GridBagConstraints();
        
        pnl.setLayout(new GridBagLayout());

        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(10,5,0,5);
        c.gridx = 0;
        c.gridy = 0;
        c.gridwidth = 2;
        pnl.add(Box.createRigidArea(new Dimension(0,10)));
        oldText = " 2    9 5\n    4 3\n8 61\n21\n 54 7 83\n       49\n     36 4\n  1 5\n5 2    9";
        parent.update(oldText);
        boardDef = new JTextArea(oldText,9,9);
        boardDef.getDocument().addDocumentListener(this);
        //boardDef.setFont(new Font("Courier",Font.BOLD,10));
        boardDef.setBorder(BorderFactory.createLoweredBevelBorder());
        boardDef.setFont(new Font("Courier New", Font.PLAIN, 18));
        pnl.add(boardDef, c);
//        pnl.add(Box.createRigidArea(new Dimension(0,10)));
        
        c.gridy = 1;
        c.gridwidth = 1;
        JPanel btnPnl = new JPanel();
        btnPnl.setBorder(BorderFactory.createLineBorder(Color.black));
        //pnl.add(btnPnl, c);
        btnPnl.setLayout(new BoxLayout(btnPnl, BoxLayout.PAGE_AXIS));

        btnSet = new JButton("Update");
        btnSolve = new JButton("Solve");
        pnl.add(btnSet, c);
        c.gridx = 1;
        //btnPnl.add(Box.createRigidArea(new Dimension(0,10)));
        pnl.add(btnSolve, c);
        btnSet.addActionListener(this);
        btnSolve.addActionListener(this);

        String[] speeds = { "maximum", "1000", "100", "50", "20", "10", "5", "3", "2", "1", "0.5", "0.2"};
        speedSel = new JComboBox(speeds);
        speedSel.setSelectedIndex(3);
        speedSel.setOpaque(true);
        speedSel.setBackground(Color.white);//new Color(200,200,255));
        speedSel.addActionListener(this);
        c.gridx = 0;
        c.gridy ++;
        c.gridwidth = 2;
        pnl.add(new JLabel("<html><center>Select speed<p>(frames per second)</center></html>", JLabel.CENTER), c);
        c.gridy ++;
        pnl.add(speedSel, c);
        
        lblStatus = new JLabel();
        lblStatus.setOpaque(true);
        lblStatus.setBackground(new Color(200,200,255));
        Font f = lblStatus.getFont();
        lblStatus.setFont(new Font(f.getFamily(), Font.PLAIN, f.getSize()));
        c.gridy ++;
        pnl.add(lblStatus, c);
        updateStatus("New puzzle");
        
        btnSet.addFocusListener(this);
        btnSolve.addFocusListener(this);
        boardDef.addFocusListener(this);
    }

    public void updateBoard()
    {
        updateStatus("New puzzle");
        parent.update(boardDef.getText());
    }
    
    public void actionPerformed(ActionEvent e) {
        Object o = e.getSource();
        if (o == btnSet) {
        	updateBoard();
        } else if (o == btnSolve) {
            //System.out.println("Solve it!");
            parent.solve();
        }
    	setSpeed();
    }
    
    public void setBoardDef(String s)
    {
    	boardDef.setText(s);
    }

	public void fixText()
    {
    	String newText = boardDef.getText();
    	int lines = 1, linelength = 0;
    	boolean valid = true;
    	for (int i = 0; i < newText.length(); i ++){
    		char c = newText.charAt(i);
    		//check for invalid character
    		//System.out.println("Good character found: "+c);
    		if ((c < '0' || c > '9') && c != '\n' && c != ' ' && c != '.') {
    			valid = false;
    		}
    		if (c == '\n') {
    			linelength = 0;
    			lines ++;
    			if (lines > Board.SIZE)
    				valid = false;
    		} else {
    			linelength ++;
    			if (linelength > Board.SIZE)
        	    	valid = false;
    		}
    	}
    	if (valid)
    		oldText = newText;
    	else
    		boardDef.setText(oldText);
    }

	public void updateStatus(String s)
	{
		lblStatus.setText("<html><b>Status:</b><p>&nbsp;&nbsp;&nbsp;&nbsp;"+s);
	}
	
	public void setSpeed()
	{
		int index = speedSel.getSelectedIndex();
		String strSpeedVal = speedSel.getItemAt(index).toString();
		if (strSpeedVal.equals("maximum")) {
			parent.setSpeed(0);
		} else {
			boolean hasPeriod = false;
			for (int c = 0; c < strSpeedVal.length(); c ++)
				if (strSpeedVal.charAt(c) == '.')
					hasPeriod = true;
			if (!hasPeriod) {
				int speedVal = new Integer (strSpeedVal).intValue();
				parent.setSpeed(1000 / speedVal);
			} else {
				float fSpeedVal = new Float (strSpeedVal).floatValue();
				fSpeedVal = 1000.f / fSpeedVal;
				parent.setSpeed((int) fSpeedVal);
			}
		}
		//System.out.println("speed is now "+ (1000 / speedVal));
	}

	public void doValidate()
	{
		if (t == null || !t.isRunning()) {
			t = new ValidateThread();
		}
	}
	public void insertUpdate(DocumentEvent e) { doValidate(); }
	public void removeUpdate(DocumentEvent e) { doValidate(); }
	public void changedUpdate(DocumentEvent e) { doValidate(); }
    public void focusGained(FocusEvent e) {
    	parent.removeHighlight();
    }
    public void focusLost(FocusEvent e) {}
	
	private class ValidateThread extends Thread
	{
		private boolean running;
		
		public ValidateThread () {
			running = true;
			start();
		}
		
		public boolean isRunning()
		{
			return running;
		}
		
		public void run()
		{
			try {
				Thread.sleep(1);
			} catch (Exception e) { }
			fixText();
			running = false;
		}
	}
}